package cn.dancepeak.system.service.impl;

import cn.dancepeak.dto.LoginDto;
import cn.dancepeak.exception.BusinessException;
import cn.dancepeak.jwt.JwtUtil;
import cn.dancepeak.jwt.Payload;
import cn.dancepeak.system.domain.Login;
import cn.dancepeak.system.domain.Menu;
import cn.dancepeak.system.mapper.LoginMapper;
import cn.dancepeak.system.service.ILoginServiceImpl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class LoginServiceImplImpl implements ILoginServiceImpl {
    @Autowired
    private LoginMapper loginMapper;

    @Override
    public String get(LoginDto loginDto) {
        //查询出和输入的相同名字和用户类型的登录者信息
        Login login = loginMapper.selectLoginInfoByUserNameAndType(loginDto);
        //接收用户名和密码
        String username = login.getUsername();
        String password = login.getPassword();
        //判断账号密码不能为空   防止有小人用Apifox之类的不走前端的账号登录获取信息
        if(StrUtil.isEmpty(username) || StrUtil.isEmpty(password)){
            throw new BusinessException("用户名或密码不能为空！");
        }
        //账号密码是否匹配? 我们现在只有伪造密码
        if(ObjectUtil.isNull(login)){
            throw new BusinessException("用户不存在，请先注册！");
        }
        //比较密码
        String s = SecureUtil.md5(login.getSalt() + loginDto.getPassword());
        if(!s.equals(login.getPassword())){
            throw new BusinessException("密码错误！");
        }
        //账号密码都对，登录成功!
        //查询出当前登录人的菜单权限
        List<Menu> menus = getLoginTree(login.getId());
        //查询出当前登录人的资源权限
        List<String> permissionSns =  loginMapper.getPermissionSnsByLoginId(login.getId());
        //将登录人信息+菜单权限+资源权限，封装成JWT串?怎么封装?
        //jwt工具类封装
        Payload payload = new Payload();
        //为了安全吧盐和加密密码隐藏
        login.setSalt(null);
        login.setPassword(null);
        //封装成JWT串
        payload.setLogininfo(login);
        payload.setMenus(menus);
        payload.setPermissions(permissionSns);
        //将JWT串返回给前端
        String jwtToken = JwtUtil.generateToken(payload);
        return jwtToken;
    }

    private List<Menu> getLoginTree(Long id) {
        //返回的菜单树顶层
        List<Menu> topMenu = new ArrayList<>();
        //查询到的所有菜单数据
        List<Menu> menus = loginMapper.getMenusByLoginId(id);
        //如果查询出来为空则返回空
        if(menus == null){
            return null;
        }
        //用map接收数据  key 为id 值为本身
        Map<Long, Menu> map = menus.stream().collect(Collectors.toMap(Menu::getId, menu -> menu));
        //遍历添加到菜单树
        for (Menu menu : menus) {
            if(menu.getParentId() == null){
                topMenu.add(menu);
            }else {
                Menu parent = map.get(menu.getParentId());
                if(parent != null){
                    parent.getChildren().add(menu);
                }
            }
        }
        return topMenu;
    }
}